// ClassFactory.h
// (c) 2008, Charles Lechasseur
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef RRO_UTILS_COM_CLASSFACTORY_H
#define RRO_UTILS_COM_CLASSFACTORY_H

#pragma once

#include <windows.h>
#include <memory>
#include <string>
#include "COM/Object.h"
#include "Exceptions/Exception.h"

#pragma warning( push )
#pragma warning( disable : 4290 )   // C++ exception specification not supported


namespace RRO {
namespace COM
{
    //
    // Enumeration of possible threading models in COM.
    //
    enum ThreadingModel
    {
        THREADING_MODEL_APARTMENT,
        THREADING_MODEL_FREE,
        THREADING_MODEL_BOTH
    };

	//
	// Creator class
	//
	// Simple abstract class that can create instances of an object.
	//
	class Creator
	{
	public:
							Creator(void);
                            Creator(const Creator&);
        Creator&            operator=(const Creator&);
		virtual				~Creator(void);

		                    //
		                    // Create
		                    //
		                    // Creates an instance of the object that this creator knows about.
		                    //
		                    // @return Newly-created object's IUnknown pointer.
                            //         The object's refcount is assumed to be 1 initially.
		                    //
		virtual IUnknown*	Create(void) = 0;
	};

    //
    // Single-inheritance creator implementation.
    //
    // Fully-working Creator template class that works for classes that use single-inheritance,
    // e.g., have IUnknown only once in their class hierarchies. This will be the case for most
    // objects derived from Object or ObjectT<>.
    //
    template<class ObjectT>
    class CreatorT : public Creator
    {
	public:
                            CreatorT(void)
                                : Creator()
							{
							}

                            CreatorT(const CreatorT<ObjectT>& p_Creator)
                                : Creator(p_Creator)
                            {
                            }

        CreatorT<ObjectT>&  operator=(const CreatorT<ObjectT>& p_Creator)
                            {
                                Creator::operator=(p_Creator);
                                return *this;
                            }

		virtual				~CreatorT(void)
							{
							}

                            //
                            // Create
                            //
                            // Returns a new instance of the type of object supported by this creator.
                            //
		virtual IUnknown*	Create(void)
                            {
                                return new ObjectT();
                            }
    };

    //
    // Exception thrown when no Creator is provided when creating a class factory.
    //
    class NullCreatorException : public Exception
    {
    public:
                                NullCreatorException(void);
                                NullCreatorException(const NullCreatorException&);
        NullCreatorException&   operator=(const NullCreatorException&);
        virtual                 ~NullCreatorException(void);

        const char*             what(void) const;
    };

	//
	// IClassFactory implementation. Simply needs a Creator that knows how to create
    // objects of the proper type.
	//
    class ClassFactory : public Object<ObjectBase<IClassFactory>, IID_IClassFactory, IClassFactory>
	{
	public:
		explicit                    ClassFactory(Creator* p_pCreator, const CLSID& p_ClassID,
                                                 const std::string& p_ProgID,
                                                 ThreadingModel p_ThreadingModel = THREADING_MODEL_APARTMENT,
                                                 const char* p_pDescription = 0) throw(NullCreatorException);
        virtual                     ~ClassFactory(void);

        const CLSID&                ClassID(void) const;
        const std::string&          ClassIDAsString(void) const;
        const std::string&          ProgID(void) const;
        const char*                 Description(void) const;

        virtual void                UpdateRegistry(bool p_Register);

		// IClassFactory methods

		STDMETHOD(CreateInstance)(IUnknown* p_pController, REFIID p_IID, void** p_ppObject);
		STDMETHOD(LockServer)(BOOL p_Lock);

    protected:
        static std::string          ClassIDToString(const CLSID& p_ClassID);

	private:
		// Creator helper to be able to create instances of our object.
        std::auto_ptr<Creator>      m_apCreator;

        // Information about the CoClass.
        CLSID                       m_ClassID;
        std::string                 m_ClassIDAsString;
        std::string                 m_ProgID;
        ThreadingModel              m_ThreadingModel;
        std::auto_ptr<std::string>  m_apDescription;

		// THESE METHODS ARE NOT IMPLEMENTED.
						            ClassFactory(const ClassFactory&);
		ClassFactory&	            operator=(const ClassFactory&);
	};

}; // namespace COM
}; // namespace RRO


#pragma warning( pop )

#endif RRO_UTILS_COM_CLASSFACTORY_H
